﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Text;
using KishOnlineCommone;

namespace KishOnlineDomain.Domain
{
    internal abstract class BaseUser
    {
       
        public abstract bool DeleteUser(int UserID);
        public abstract ResultDTO<UserDTO> UpdateUser(UserDTO UserInfo);
        public abstract ResultDTO<UserDTO> GetUser(int UserID);
        public virtual List<UserDTO> GetAllUser()
        {
            using (var db = Common.Utility.GetDataContext())
            {
                List<UserDTO> Users = new List<UserDTO>();
                Users = db.Users.Where(q => !q.IsDeleted && !q.Master).Select(q => new UserDTO
                {
                    ID = q.ID,
                    FirstName = q.FirstName,
                    LastName = q.LastName,
                    DateCreated = q.DateCreated,
                    Address = q.Address,
                    Email = q.Email,
                    Telephone = q.Telphone
                }).ToList();
                return Users;
            }
        }
        public static ResultDTO<int> CreateUser(UserDTO UserInfo)
        {
            ResultDTO<int> Result = new ResultDTO<int>();            
            if (!IsCurrentUserNameExist(UserInfo.Email))
            {
                using (var db = Common.Utility.GetDataContext())
                {
                    KishOnlineDataAccess.User NewUser = new KishOnlineDataAccess.User();
                    NewUser.FirstName = UserInfo.FirstName;
                    NewUser.LastName = UserInfo.LastName;
                    NewUser.Email = UserInfo.Email;
                    NewUser.Address = UserInfo.Address;
                    NewUser.Telphone = UserInfo.Telephone;
                    NewUser.DateCreated = DateTime.Now.Date;
                    NewUser.Master = false;
                    NewUser.PassWord = BaseUser.GetStringHash(UserInfo.Password);                    
                    db.Users.InsertOnSubmit(NewUser);
                    List<KishOnlineDataAccess.Role_User> Role_Users = UserInfo.Roles.Select(q => new KishOnlineDataAccess.Role_User
                    {
                        User= NewUser,
                        RoleID = (int)q,                        
                    }).ToList();
                    db.Role_Users.InsertAllOnSubmit(Role_Users);   //UserInfo.Roles
                    db.SubmitChanges();
                    Result.Data = NewUser.ID;
                }                
                Result.IsSucceed = true;
                Result.Message = MessageReader.Get(MessageType.Event, 1);
                Result.Message.Type = MessageType.Event;
            }
            else
            {
                Result.IsSucceed = false;
                Result.Message = MessageReader.Get(MessageType.Error, 5);
            }
            return Result;
        }
        public static ResultDTO Loggin(string UserName, string Password)
        {
            ResultDTO result = new ResultDTO();
            using (var db = Common.Utility.GetDataContext())
            {
                var user = db.Users.FirstOrDefault(m => m.Email == UserName && !m.IsDeleted);
                if (user == null)
                {
                    result.IsSucceed = false;
                    result.Message = MessageReader.Get(MessageType.Error, 4);

                }
                else
                {
                    var pass = user.PassWord;
                    bool isAuthenticated = CompareHash(Password, pass);
                    if (isAuthenticated)
                    {
                        result.IsSucceed = true;
                        UserDTO CurrentUser = new UserDTO();
                        CurrentUser.Email = user.Email;
                        CurrentUser.FirstName = user.FirstName;
                        CurrentUser.LastName = user.LastName;
                        CurrentUser.Telephone = user.Telphone;
                        CurrentUser.Address = user.Address;
                        CurrentUser.IsActive = user.IsActive;
                        CurrentUser.ID = user.ID;
                        CurrentUser.Roles = GetUserRoles(user.ID);
                        Common.Utility.SetLogginSession(CurrentUser);
                    }
                    else
                    {
                        result.IsSucceed = false;
                        result.Message = MessageReader.Get(MessageType.Error, 7);

                    }
                }
            }
            return result;
        }
        public bool LoggOut()
        {
            System.Web.HttpContext.Current.Session["User"] = null;
            return true;
        }

        public static List<RoleTypes> GetUserRoles(int UserID)
        {
            List<RoleTypes> CurrentRoles = new List<RoleTypes>();
            using (var db = Common.Utility.GetDataContext())
            {
                CurrentRoles = (from RolesObj in db.Roles
                                join User_Roles in db.Role_Users
                                on RolesObj.ID equals User_Roles.RoleID
                                where User_Roles.UserID.Equals(UserID)
                                select (RoleTypes)RolesObj.ID).ToList();
            }
            return CurrentRoles;
        }

        protected static bool CompareHash(string attemptedPassword, string pass)
        {
            string base64AttemptedHash = Convert.ToBase64String(GetHash(attemptedPassword));
            return pass == base64AttemptedHash;
        }

        // more security by this =>public static byte[] GetHash(string password, string salt)
        private static byte[] GetHash(string password)
        {
            //byte[] unhashedBytes = Encoding.Unicode.GetBytes(String.Concat(salt, password));
            byte[] unhashedBytes = Encoding.Unicode.GetBytes(password);

            System.Security.Cryptography.SHA256Managed sha256 = new System.Security.Cryptography.SHA256Managed();
            byte[] hashedBytes = sha256.ComputeHash(unhashedBytes);

            return hashedBytes;
        }        

        protected static string GetStringHash(string password)
        {
            return Convert.ToBase64String(BaseUser.GetHash(password));
        }
        
        protected static bool IsCurrentUserNameExist(string UserName)
        {
            using (var db = Common.Utility.GetDataContext())
            {
                var Count = db.Users.Where(q => q.Email == UserName).Count();
                return Count > 0;
            }
        }
    }

    internal class Member : BaseUser
    {        
        public override bool DeleteUser(int UserID)
        {
            using (var db = Common.Utility.GetDataContext())
            {
                var User = db.Users.Where(q => q.ID == UserID).SingleOrDefault();
                if (User != null)
                {
                    User.IsDeleted = true;
                    db.SubmitChanges();
                    return true;
                }
                else
                {
                    return false;
                }

            }
        }

        public override ResultDTO<UserDTO> UpdateUser(UserDTO UserInfo)
        {
            using (var db = Common.Utility.GetDataContext())
            {
                KishOnlineDataAccess.User UserDTO = new KishOnlineDataAccess.User();
                UserDTO = db.Users.Where(q => q.ID == UserInfo.ID && !q.IsDeleted).SingleOrDefault();
                if (UserDTO != null)
                {
                    UserDTO.FirstName = UserInfo.FirstName;
                    UserDTO.LastName = UserInfo.LastName;
                    UserDTO.DateCreated = UserInfo.DateCreated;
                    UserDTO.Address = UserInfo.Address;
                    UserDTO.Email = UserInfo.Email;
                    UserDTO.Telphone = UserInfo.Telephone;
                    UserDTO.IsActive = UserInfo.IsActive;
                    db.SubmitChanges();
                    ResultDTO<UserDTO> Result = new ResultDTO<UserDTO>();
                    Result.Data = UserInfo;
                    Result.IsSucceed = true;
                    Result.Message = MessageReader.Get(MessageType.Event, 8); //"User Update successfully."
                    return Result;
                }
                else
                {
                    ResultDTO<UserDTO> Result = new ResultDTO<UserDTO>();
                    Result.Data = null;
                    Result.IsSucceed = false;
                    Result.Message = MessageReader.Get(MessageType.Error, 32);//"User update failed."
                    return Result;
                }
            }
        }

        public override ResultDTO<UserDTO> GetUser(int UserID)
        {
            ResultDTO<UserDTO> Result = new ResultDTO<UserDTO>();
            using (var db = Common.Utility.GetDataContext())
            {
                UserDTO UserDTO = new UserDTO();
                var User = db.Users.Where(q => q.ID == UserID && !q.IsDeleted).SingleOrDefault();
                if (User != null)
                {
                    UserDTO.ID = User.ID;
                    UserDTO.FirstName = User.FirstName;
                    UserDTO.LastName = User.LastName;
                    UserDTO.DateCreated = User.DateCreated;
                    UserDTO.Address = User.Address;
                    UserDTO.Email = User.Email;
                    UserDTO.Telephone = User.Telphone;
                    Result.Data = UserDTO;
                    Result.IsSucceed = true;
                }
                else
                {
                    Result.Data = null;
                    Result.IsSucceed = false;
                    Result.Message = MessageReader.Get(MessageType.Error, 32);
                }
                
                return Result;
            }
        }       
    }

    internal class Admin : BaseUser
    {        
        public override bool DeleteUser(int UserID)
        {
            using (var db = Common.Utility.GetDataContext())
            {
                var User = db.Users.Where(q => q.ID == UserID).SingleOrDefault();
                if (User != null)
                {
                    User.IsDeleted = true;
                    db.SubmitChanges();
                    return true;
                }
                else
                {
                    return false;
                }

            }
        }

        public override ResultDTO<UserDTO> UpdateUser(UserDTO UserInfo)
        {
            using (var db = Common.Utility.GetDataContext())
            {
                KishOnlineDataAccess.User UserDTO = new KishOnlineDataAccess.User();
                UserDTO = db.Users.Where(q => q.ID == UserInfo.ID && !q.IsDeleted).SingleOrDefault();
                if (UserDTO != null)
                {
                    UserDTO.FirstName = UserInfo.FirstName;
                    UserDTO.LastName = UserInfo.LastName;
                    UserDTO.DateCreated = UserInfo.DateCreated;
                    UserDTO.Address = UserInfo.Address;
                    UserDTO.Email = UserInfo.Email;
                    UserDTO.Telphone = UserInfo.Telephone;
                    UserDTO.IsActive = UserInfo.IsActive;
                    db.SubmitChanges();
                    ResultDTO<UserDTO> Result = new ResultDTO<UserDTO>();
                    Result.Data = UserInfo;
                    Result.IsSucceed = true;
                    Result.Message = MessageReader.Get(MessageType.Event, 8); //"User Update successfully."
                    return Result;
                }
                else
                {
                    ResultDTO<UserDTO> Result = new ResultDTO<UserDTO>();
                    Result.Data = null;
                    Result.IsSucceed = false;
                    Result.Message = MessageReader.Get(MessageType.Error, 32);//"User update failed."
                    return Result;
                }
            }
        }

        public override ResultDTO<UserDTO> GetUser(int UserID)
        {
            ResultDTO<UserDTO> Result = new ResultDTO<UserDTO>();
            using (var db = Common.Utility.GetDataContext())
            {
                UserDTO UserDTO = new UserDTO();
                var User = db.Users.Where(q => q.ID == UserID && !q.IsDeleted).SingleOrDefault();
                if (User != null)
                {
                    UserDTO.ID = User.ID;
                    UserDTO.FirstName = User.FirstName;
                    UserDTO.LastName = User.LastName;
                    UserDTO.DateCreated = User.DateCreated;
                    UserDTO.Address = User.Address;
                    UserDTO.Email = User.Email;
                    UserDTO.Telephone = User.Telphone;
                    Result.Data = UserDTO;
                    Result.IsSucceed = true;
                }
                else
                {
                    Result.Data = null;
                    Result.IsSucceed = false;
                    Result.Message = MessageReader.Get(MessageType.Error, 32);
                }

                return Result;
            }
        }
    }
}
